package ltd.hyangyang.rpc.common.extension;

import lombok.Builder;
import lombok.Data;
import lombok.SneakyThrows;
import ltd.hyangyang.rpc.common.bean.RpcProperties;
import ltd.hyangyang.rpc.common.exception.RpcException;
import ltd.hyangyang.rpc.common.utils.SingletonFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

public class ExtensionLoader<S> {

    static ConcurrentHashMap<Class<?>, ExtensionLoader<?>> cacheLoader = new ConcurrentHashMap<>();

    ConcurrentHashMap<String,Holder<S>> cacheExtension = new ConcurrentHashMap<>();

    ConcurrentHashMap<String,Class<?>> extensionClass = new ConcurrentHashMap<>();
    static final String EXTENSION_CLASS_PATH = "META-INF/extension/";

    ClassLoader classLoader;
    Class<?> type;

    RpcProperties rpcProperties;

    ExtensionLoader(Class<?> type) {
        this.type = type;
        rpcProperties = SingletonFactory.getSingletonBean(RpcProperties.class);
    }

    //获得一个扩展加载器
    public static  <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) throws InstantiationException, IllegalAccessException {
        //2. 根据type的类型从cacheLoader 中获取extensionLoader的值
        ExtensionLoader<T> extensionLoader = (ExtensionLoader<T>) cacheLoader.get(type);

        //4. 如果值为空，构建一个ExtensionLoader实例
        if (extensionLoader == null) {
            cacheLoader.putIfAbsent(type, new ExtensionLoader<>(type));
            extensionLoader= (ExtensionLoader<T>) cacheLoader.get(type);
        }
        return extensionLoader;

    }

    //通过extensionLoader获得扩展
    @SneakyThrows
    public S getExtension(){
        String registryType = rpcProperties.getRegistryType();
        return getExtension(registryType);

    }
    public S getExtension(String name) throws IOException, InstantiationException, IllegalAccessException {

        Holder<S> holder = cacheExtension.get(name);
        if (holder==null){
            //如果为null，则构造实例
            cacheExtension.putIfAbsent(name,new Holder<S>());
            holder = cacheExtension.get(name);
        }
        S object = holder.getObject();
        if (object==null){
            //如果object为空，则创建extension实例，
            object = createExtension(name);
        }

        return object;
    }

    public S createExtension(String name) throws IOException, InstantiationException, IllegalAccessException {

        //判断在该实例中是否有name的实现
        Class<?> clazz = extensionClass.get(name);
        if (clazz!=null) {
            return (S) clazz.newInstance();
        }

        //如果在extensionClass中为空，则加载配置文件获取全部扩展的全限定名，然后将扩展根据name添加到extensionClass
        //加载文件，获取实现类的全限定名
        List<String> resources = loadImplCanonicalName();

        //得到和name匹配的类的全限定名
        String canonicalName = getCanonicalName(resources, name);

        Class<?> loadClass = loadClass(canonicalName);
        extensionClass.putIfAbsent(name,loadClass);

        return (S) loadClass.newInstance();
    }

    String getCanonicalName(List<String> resources,String name){
        for (String line : resources) {
            line = line.trim();
            String[] strings = line.split("#");
            if (strings.length<=1&&strings[0].contains("#")){
                continue;
            }
            String usefulConfiguration = strings[0];

            String[] keyOrCanonicalName = usefulConfiguration.split("=");
            if (keyOrCanonicalName.length<=1||!name.equals(keyOrCanonicalName[0])){
                continue;
            }
            return keyOrCanonicalName[1];
        }
        //执行到这个位置表示没有找到关于name的配置，抛出异常
        throw new RpcException("没有找到关于"+name+"的实现类");
    }

    public List<String> loadImplCanonicalName() throws IOException {
        List<String> resources = new ArrayList<>();
        String canonicalName = type.getCanonicalName();
        //读取文件
        classLoader = type.getClassLoader();
        String extensionPath = EXTENSION_CLASS_PATH+canonicalName;
        URL url = classLoader.getResource(extensionPath);
        InputStream inputStream = url.openStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String line = null;
        while ((line = bufferedReader.readLine())!=null){
            resources.add(line);
        }
        return resources;
    }

//    //加载所有的扩展类，并将扩展类添加到extensionClass中
//    public void loadAllClasses(List<String> canonicalNames){
//        for (String canonicalName : canonicalNames) {
//            classLoader
//        }
//    }

    public Class<?> loadClass(String canonicalName){
        Class<?> loadClass = null;
        try {
            loadClass = classLoader.loadClass(canonicalName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return loadClass;
    }


}
